<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8" />
  <title>内容页</title>
  <link rel="stylesheet" href="css/cssreset.css" />
  <link rel="stylesheet" href="theme/atom-one-light.css" />
  <link rel="stylesheet" href="css/blog.min.css" />
</head>

<body>

  <header class="nav-bar">
    <div class="nav">
      <a class="brand pull-left" href="#"></a>
      <nav class="nav-wraper">
        <ul class="container">
          <li>
            <a href="#">文章</a>
          </li>
          <li class="active">
            <a href="#">归档</a>
          </li>
          <li>
            <a href="#">标签</a>
          </li>
          <li>
            <a href="#">关于</a>
          </li>
        </ul>
      </nav>
      <div class="search-bar pull-right"></div>
    </div>

    <div class="nav-line">
      <div class="nav-wraper">
        <div class="container currrent">
          <div class="cur"></div>
        </div>
      </div>
    </div>
  </header>

  <div id="" style="margin-top:65px;">
    <div class="container">

      <!-- wenzhang -->
      <div class="headline">麦肯锡重磅报告：汽车半导体的机遇与挑战|半导体行业观察</div>

      <article class="markdown">
        <h2>概述</h2>
        <p>Javascript语言的执行环境是"单线程"（single thread）。所谓"单线程"，就是指一次只能完成一件任务。如果有多个任务，就必须排队，前面一个任务完成，再执行后面一个任务，以此类推。</p>
        <p>这种模式的好处是实现起来比较简单，执行环境相对单纯；坏处是只要有一个任务耗时很长，后面的任务都必须排队等着，会拖延整个程序的执行。常见的浏览器无响应（假死），往往就是因为某一段Javascript代码长时间运行（比如死循环），导致整个页面卡在这个地方，其他任务无法执行。</p>
        <p>为了解决这个问题，Javascript语言将任务的执行模式分成两种：同步（Synchronous）和异步（Asynchronous）。</p>
        <p>"同步模式"就是上一段的模式，后一个任务等待前一个任务结束，然后再执行，程序的执行顺序与任务的排列顺序是一致的、同步的；"异步模式"则完全不同，每一个任务有一个或多个回调函数（callback），前一个任务结束后，不是执行后一个任务，而是执行回调函数，后一个任务则是不等前一个任务结束就执行，所以程序的执行顺序与任务的排列顺序是不一致的、异步的。</p>
        <p>"异步模式"非常重要。在浏览器端，耗时很长的操作都应该异步执行，避免浏览器失去响应，最好的例子就是Ajax操作。在服务器端，"异步模式"甚至是唯一的模式，因为执行环境是单线程的，如果允许同步执行所有http请求，服务器性能会急剧下降，很快就会失去响应。</p>
        <p>以下总结了"异步模式"编程的4种方法，理解它们可以让你写出结构更合理、性能更出色、维护更方便的JavaScript程序。</p>
        <h2>回调函数</h2>
        <p>回调函数是异步编程最基本的方法。</p>
        <p>假定有两个函数f1和f2，后者等待前者的执行结果。</p>
        <pre><code class="lang-javascript">f1();
f2();
</code></pre>
        <p>如果f1是一个很耗时的任务，可以考虑改写f1，把f2写成f1的回调函数。</p>
        <pre><code class="lang-javascript">function f1(callback){
    setTimeout(function () {
        // f1的任务代码
        callback();
    }, 1000);
}
</code></pre>
        <p>执行代码就变成下面这样：</p>
        <pre><code class="lang-javascript">f1(f2);
</code></pre>
        <p>采用这种方式，我们把同步操作变成了异步操作，f1不会堵塞程序运行，相当于先执行程序的主要逻辑，将耗时的操作推迟执行。</p>
        <p>回调函数的优点是简单、容易理解和部署，缺点是不利于代码的阅读和维护，各个部分之间高度
          <a href="http://en.wikipedia.org/wiki/Coupling_(computer_programming">耦合</a>（Coupling），使得程序结构混乱、流程难以追踪（尤其是回调函数嵌套的情况），而且每个任务只能指定一个回调函数。</p>
        <h2>事件监听</h2>
        <p>另一种思路是采用事件驱动模式。任务的执行不取决于代码的顺序，而取决于某个事件是否发生。</p>
        <p>还是以f1和f2为例。首先，为f1绑定一个事件（这里采用的jQuery的
          <a href="http://api.jquery.com/on/">写法</a>）。</p>
        <pre><code class="lang-javascript">f1.on('done', f2);
</code></pre>
        <p>上面这行代码的意思是，当f1发生done事件，就执行f2。然后，对f1进行改写：</p>
        <pre><code class="lang-javascript">function f1(){
    setTimeout(function () {
        // f1的任务代码
        f1.trigger('done');
    }, 1000);
}
</code></pre>
        <p>f1.trigger('done')表示，执行完成后，立即触发done事件，从而开始执行f2。</p>
        <p>这种方法的优点是比较容易理解，可以绑定多个事件，每个事件可以指定多个回调函数，而且可以"
          <a href="http://en.wikipedia.org/wiki/Decoupling">去耦合</a>"（Decoupling），有利于实现模块化。缺点是整个程序都要变成事件驱动型，运行流程会变得很不清晰。</p>
        <h2>发布/订阅</h2>
        <p>"事件"完全可以理解成"信号"，如果存在一个"信号中心"，某个任务执行完成，就向信号中心"发布"（publish）一个信号，其他任务可以向信号中心"订阅"（subscribe）这个信号，从而知道什么时候自己可以开始执行。这就叫做"
          <a href="http://en.wikipedia.org/wiki/Publish-subscribe_pattern">发布/订阅模式</a>"（publish-subscribe pattern），又称"
          <a href="http://en.wikipedia.org/wiki/Observer_pattern">观察者模式</a>"（observer pattern）。</p>
        <p>这个模式有多种
          <a href="http://msdn.microsoft.com/en-us/magazine/hh201955.aspx">实现</a>，下面采用的是Ben Alman的
          <a href="https://gist.github.com/661855">Tiny Pub/Sub</a>，这是jQuery的一个插件。</p>
        <p>首先，f2向"信号中心"jQuery订阅"done"信号。</p>
        <pre><code class="lang-javascript">jQuery.subscribe("done", f2);
</code></pre>
        <p>然后，f1进行如下改写：</p>
        <pre><code class="lang-javascript">function f1(){
    setTimeout(function () {
        // f1的任务代码
        jQuery.publish("done");
    }, 1000);
}
</code></pre>
      </article>


      <!-- wenzhang -->
    </div>


  </div>



  <script src="vendor/esl.js" data-main="js/blog"></script>
  <script>
    require.config({
      baseUrl: './',
      paths: {
        "jquery": "./vendor/jquery/jquery-1.11.1",
        "hljs": "./vendor/highlight.min",
        "jquery.navslider": "./js/jquery.navslider"
      }
    })
  </script>

</body>

</html>